package com.fingard.dsp.bank.directbank.srcb01;

import java.io.File;
import java.sql.Connection;
import java.util.*;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

import com.fingard.FGBiz;
import com.fingard.constant.Format;
import com.fingard.db.JDBCHelper;
import com.fingard.dsp.bank.directbank.bankInterface.IBatPayRec;
import com.fingard.dsp.bank.reqrespobj.batpayrec.ReqBatPayRec;
import com.fingard.dsp.bank.reqrespobj.batpayrec.ReqQryBatPayRec;
import com.fingard.dsp.bank.reqrespobj.batpayrec.RetAtsBatPayRec;
import com.fingard.dsp.bank.reqrespobj.batpayrec.RetAtsQryBatPayRec;
import com.fingard.dsp.bank.reqrespobj.batpayrec.detail.RetAtsBatPayRecDetail;
import com.fingard.dsp.bank.reqrespobj.single.detail.ReqPayRecDetail;
import com.fingard.io.FileHelper;
import com.fingard.text.StringHelper;
import com.fingard.xml.XmlTextReader;
import com.fingard.xml.XmlTextWriter;

/**
 * @author XueJy on 2018/8/21.
 * @version 1.0
 */
public class SRCB01BatPayRec extends SRCB01Base implements IBatPayRec, Runnable {
    private String batchNo = "";
    private String payAct = "";
    private String retBatchNo = "";
    private static final String INSERTSEQ = "INSERT INTO REQSEQIDMAPPING(URID,BANKCODE,TRANSDATE,REQSEQID,BANKREQSEQID) values (?,?,?,?,?);";
    private static final String SELECTSEQ = "SELECT BANKREQSEQID FROM REQSEQIDMAPPING WHERE REQSEQID=?;";

    /**
     * 批量支付
     */
    @Override
    public RetAtsBatPayRec d_1988_BatPay(final ReqBatPayRec p_req1988) throws Exception {

        //创建返回对象
        RetAtsBatPayRec retAts = new RetAtsBatPayRec(p_req1988.reqHeader);
        //returnAts报文头
        retAts.retHeader.bankCode = p_req1988.reqHeader.bankCode;
        retAts.retHeader.transType = p_req1988.reqHeader.transType;
        retAts.retHeader.transSeqID = p_req1988.reqHeader.transSeqID;
        //支付请求码
        batchNo = p_req1988.reqBatchNO;
        retAts.reqSeqID = batchNo;
        //请求登陆
        String[] loginResult = login();
        if (loginResult[0].length() != 0) {
            retAts.respCode = "0";
            retAts.respInfo ="登陆错误:"+ loginResult[1];
            retAts.transState = "支付登陆失败";
            retAts.payInfoCode = "支付登陆失败";
            retAts.writeRetToATS();
            return retAts;
        }
        //总笔数,总金额
        String strTotalNum = p_req1988.totalNum;
        String strTotalAmt = p_req1988.totalAmt;
        payAct = p_req1988.ownAct;
        String actName = p_req1988.ownActName;
        //新建发送银行报文
        XmlTextWriter xmlWriterStep1 = new XmlTextWriter();
        String transCode = getBankConfig().getMapValueByKey("transCode", "1988");
        String packetId = Format.Date8Format.format(new Date()) + p_req1988.reqBatchNO;
        writeCommonHeader(xmlWriterStep1, transCode, "");
        //报文体参数
        List<String[]> paramStep1 = new ArrayList<String[]>();
        StringBuilder sb = new StringBuilder();
        while (p_req1988.readRecord()) {
            ReqPayRecDetail detail = p_req1988.readedDetail;
            sb.append(detail.recAct);
            sb.append(",");
            sb.append(detail.recName);
            sb.append(",");
            sb.append(detail.payAmount);
            sb.append(",");
            sb.append("\r\n");
        }
        sb.delete(sb.length() - 2, sb.length());
        //上传文件名，来盘文件名规则：自然日期（YYYYMMDD，共8位）+序号（3位）.txt(序号需要按照001,002…递增格式上送)
        String bakUpPath = getDataFileDirectory(new Date());
        int maxBatch = 0;
        File dataFileDir = new File(StringHelper.trimEnd(bakUpPath, File.separator) + File.separator + "batPay");
        if (dataFileDir.exists()) {
            int len = dataFileDir.listFiles().length;
            if (len > 0) {
                maxBatch = len + 1;
            } else {
                maxBatch = 1;
            }
        } else {
            maxBatch = 1;
        }

        String payFileName = Format.Date8Format.format(new Date()) + String.format("%3s", maxBatch).replace(" ", "0") + ".txt";
        String tmpBatPayPath = StringHelper.trimEnd(bakUpPath, File.separator) + File.separator + "batPay" + File.separator + payFileName;
        //批次号文件名映射文件
        String tmpLocalMarkPath = StringHelper.trimEnd(bakUpPath, File.separator) + File.separator + "batBatchMap" + File.separator + batchNo + ".txt";
        FileHelper.writeFile(tmpLocalMarkPath, payFileName, getCharset());
        WriteBankLogLn2("批次号映射文件路径: " + tmpLocalMarkPath);
        //?????????????????GBK 收款名字会乱码 测试UTF-8
        FileHelper.writeFile(tmpBatPayPath, sb.toString(), "UTF-8");
        WriteBankLogLn2("批量交易上传文件备份路径: " + tmpBatPayPath);
        //交易步骤
        paramStep1.add(new String[]{"payrollStep", "01"});
        //20171225001.txt
        //上传文件名，来盘文件名规则：自然日期（YYYYMMDD，共8位）+序号（3位）.txt(序号需要按照001,002…递增格式上送)
        //文件名
        paramStep1.add(new String[]{"fileName", payFileName});
        //	总笔数
        paramStep1.add(new String[]{"totalCount", strTotalNum});
        //总金额
        paramStep1.add(new String[]{"totalAmount", strTotalAmt});
        //客户号
        paramStep1.add(new String[]{"groupId", payAct});
        //客户业务类型
        paramStep1.add(new String[]{"buscisCode", getBankConfig().getValueAsString("buscisCode")});
        //预留字段一
        paramStep1.add(new String[]{"remark1", ""});
        //预留字段二
        paramStep1.add(new String[]{"remark2", ""});
        writeBodyParams(xmlWriterStep1, paramStep1);
        //String[] res=   sendToBank(xmlWriterStep1.toXmlString());
        String xmlFileName = Format.Date8Format.format(new Date()) + String.format("%3s", maxBatch).replace(" ", "0") + "-0090-01" + ".xml";
        String tmpxmlPath = StringHelper.trimEnd(bakUpPath, File.separator) + File.separator + "xml" + File.separator + xmlFileName;
        WriteBankLogLn2("批次号对应银行报文路径: " + tmpxmlPath);
        WriteBankLogStep2(xmlWriterStep1.toXmlString());

        FileHelper.writeFile(tmpxmlPath, xmlWriterStep1.toXmlString(), getCharset());
        String[] resultStep1 = sendToBank(new String[]{tmpxmlPath, tmpBatPayPath});
        if (resultStep1[0].length() == 0) {
            StringBuilder tmpSbMsg = new StringBuilder();
            XmlTextReader tmpBkReader = loadBankRespXmlReader(resultStep1[1], tmpSbMsg);
            if (tmpBkReader != null) {
                String tmpRetCode = tmpBkReader.getFirstText("/response/head/ret_code");
                if ("000000".equals(tmpRetCode)) {
                    retBatchNo = tmpBkReader.getFirstText("/response/body/batchNo");
                    Connection conn = FGBiz.getLocalDbConn();
                    String uuid = UUID.randomUUID().toString().replaceAll("-", "");
                    //建立批量流水号和银行返回流水号的映射关系
                    JDBCHelper.update(conn, INSERTSEQ, new Object[]{uuid, p_req1988.reqHeader.bankCode, Format.Date8Format.format(new Date()), batchNo, retBatchNo});
                    WriteBankLogLn("批量步骤1提交成功。");
                    Executor e = Executors.newScheduledThreadPool(3);
                    e.execute(this);
                    retAts.respCode = "0";
                    retAts.transState = "S1+" + tmpRetCode;
                    retAts.payInfoCode = "S1+" + tmpRetCode;
                    retAts.respInfo = "支付请求发起成功,请20分钟后查询。";
                    retAts.writeRetToATS();
                    return retAts;
                } else {
                    WriteBankLogLn("支付请求发起失败，原因为：" + tmpBkReader.getFirstText("/response/head/err_msg"));
                    retAts.respCode = "0";
                    retAts.payInfoCode = "S1+" + tmpRetCode;
                    retAts.transState = "S1+" + tmpRetCode;
                    retAts.respInfo = tmpBkReader.getFirstText("/response/head/err_msg");
                    retAts.writeRetToATS();
                    return retAts;
                }
            } else {
                WriteBankLogLn("步骤一发送成功，银行返回报文解析失败，报文内容为：" + resultStep1[1]);
                retAts.respCode = "-1";
                retAts.respInfo = (tmpSbMsg.toString());
                retAts.writeRetToATS();
                return retAts;
            }
        } else {
            retAts.respCode = "-1";
            retAts.respInfo = resultStep1[1];
            retAts.writeRetToATS();
            return retAts;
        }
    }

    /**
     * 批量支付结果查询
     */
    @Override
    public RetAtsQryBatPayRec d_1998_QryBatPay(ReqQryBatPayRec p_req1998) throws Exception {

        RetAtsQryBatPayRec retAts = new RetAtsQryBatPayRec(p_req1998.reqHeader);
        //支付请求码
        batchNo = p_req1998.reqBatchNO;
        retAts.reqSeqID = batchNo;
        try {
            //请求登陆
            String[] loginResult = login();
            if (loginResult[0].length() != 0) {
                retAts.respCode = "-1";
                //通讯错误：交易码2001，连接外围系统EntBanking时发生错误。
                retAts.respInfo = loginResult[1];
                retAts.writeAfterDetail();
                return retAts;
            }
            String[] result = queryFileStatusAndConfirm(batchNo, p_req1998.ownAct, p_req1998.getBgnDateTime());
            if ("-1".equals(result[0])) {
                retAts.respCode = "-1";
                retAts.respInfo = result[1];
                retAts.writeAfterDetail();
                return retAts;
            } else if ("-9".equals(result[0])) {
                //支付失败
                retAts.respCode = "0";
                retAts.respInfo = result[1];
                retAts.transState = "S2+000000+9";
                retAts.payInfoCode = "S2+000000+9";
                retAts.writeAfterDetail();
                return retAts;
            } else if ("-2".equals(result[0])) {
                //步骤二失败
                retAts.respCode = "0";
                retAts.respInfo = result[2];
                retAts.transState = "S2+" + result[1];
                retAts.payInfoCode = "S2+" + result[1];
                retAts.writeAfterDetail();
                return retAts;
            } else if ("-3".equals(result[0])) {
                //步骤二失败 或步骤三 失败
                retAts.respCode = "0";
                retAts.respInfo = result[2];
                retAts.transState = "S3+" + result[1];
                retAts.payInfoCode = "S3+" + result[1];
                retAts.writeAfterDetail();
                return retAts;
            } else if ("1" .equals(result[0])) {
                retAts.respCode = "0";
                retAts.respInfo = result[1];
                retAts.transState = "S4+000000+1";
                retAts.payInfoCode = "S4+000000+1";
            } else if ("0" .equals(result[0])) {
                String payFileName = result[1];
                XmlTextWriter xmlWriterStep4 = new XmlTextWriter();
//                String transCode = getBankConfig().getMapValueByKey("transCode", "1988");
                String transCode = "0080";
                String packetId = Format.Date8Format.format(new Date()) + batchNo;
                writeCommonHeader(xmlWriterStep4, transCode, packetId);
                List<String[]> step4Params = new ArrayList<String[]>();
                    /* payrollStep 代发步骤	char /2 非空 固定值：04
                    PayerAcctNo 付款账号 非空 付款账号
                    fileName 文件名	char /15 非空 上传的文件名
                    StartNum 查询起始数	char /10 非空 查询起始数 示例：2 ，表示从第2笔查询
                    范围：大于等于1，小于文本总笔数
                    EndNum 查询结束数	char /10 非空 范围：大于1，小于文本总笔数
                    remark1 预留字段一	char/10 预留字段一
                    remark2 预留字段二	char/10 预留字段二*/
                step4Params.add(new String[]{"payrollStep", "04"});
                //从SQLlite中取retBatchNo
                Connection conn = FGBiz.getLocalDbConn();
                Map<String, Object> selMap = JDBCHelper.execQuerySingle(conn, SELECTSEQ, new Object[]{batchNo});
                if (selMap != null & selMap.size() > 0) {
                    retBatchNo = selMap.get("BANKREQSEQID").toString();
                }
                step4Params.add(new String[]{"batchNo", retBatchNo});
                step4Params.add(new String[]{"startCount", "1"});
                step4Params.add(new String[]{"step", p_req1998.totalNum});
                step4Params.add(new String[]{"remark1", ""});
                step4Params.add(new String[]{"remark2", ""});
                writeBodyParams(xmlWriterStep4, step4Params);
                String[] tmpStrRet = sendToBank(xmlWriterStep4.toXmlString());
                List<RetAtsBatPayRecDetail> details = new ArrayList<RetAtsBatPayRecDetail>();
                if (tmpStrRet[0].length() == 0) {
                    StringBuilder tmpSbMsg = new StringBuilder();
                    XmlTextReader tmpBkReader = loadBankRespXmlReader(tmpStrRet[1], tmpSbMsg);
                    if (tmpBkReader != null) {
                        String tmpRetCode = tmpBkReader.getFirstText("/response/head/ret_code");
                        if ("000000" .equals(tmpRetCode)) {
                            retAts.respCode = "0";
                            retAts.reqSeqID = batchNo;
                            retAts.respInfo = "查询成功";
                            while (tmpBkReader.read("/response/body/tran_record_list/record")) {
                                RetAtsBatPayRecDetail tmpRetDetail = new RetAtsBatPayRecDetail();
                                String payStatus = tmpBkReader.readedXElement.getSingleText("PayStatus");
                                tmpRetDetail.recAct = tmpBkReader.readedXElement.getSingleText("PayeeAcctNo");
                                tmpRetDetail.recName = tmpBkReader.readedXElement.getSingleText("PayeeAcctName");
                                tmpRetDetail.payAmount = tmpBkReader.readedXElement.getSingleText("PayAmount");
                                tmpRetDetail.postScript = tmpBkReader.readedXElement.getSingleText("UserRem");
                                //FailMassage中  成功也返回 交易成功  支付中返回 已发送
                                String msg = tmpBkReader.readedXElement.getSingleText("FailMassage");
                                tmpRetDetail.memo = msg;
                                tmpRetDetail.payInfoCode = msg;
                                if (msg.contains("已退款")) {
                                    payStatus = "R" + payStatus;
                                }
                                //1、处理中
                                //4、代表成功
                                //5、代表失败
                                tmpRetDetail.result = "S4+" + tmpRetCode + "+" + payStatus;

                                details.add(tmpRetDetail);
                            }
                            for (RetAtsBatPayRecDetail detail : details) {
                            retAts.writeRetDetail(detail);
                            }
                        } else {
                            retAts.respCode = "0";
                            retAts.payInfoCode = "S4+" + tmpRetCode;
                            retAts.transState = "S4+" + tmpRetCode;
                            retAts.respInfo = tmpBkReader.getFirstText("/response/head/err_msg");
                        }
                    } else {
                        retAts.respCode = "-1";
                        retAts.respInfo = tmpSbMsg.toString();
                    }
                } else {
                    retAts.respCode = "-1";
                    retAts.respInfo = tmpStrRet[1];
                }
//                } else {
//                    WriteBankLogLn("路径:" + payFilePath + "找不到付款备份文件。");
//                    retAts.respCode = "-1";
//                    retAts.respInfo = "找不到付款备份文件。";
//                    retAts.writeAfterDetail();
//                    return retAts;
//                }
            }



        } catch (Exception e) {
            retAts.respCode = "-1";
            retAts.respInfo = e.getMessage();
        }
        retAts.writeAfterDetail();
        return retAts;
    }

    /**
     * 批量代收(代扣)
     */
    @Override
    public RetAtsBatPayRec d_9188_BatPay(ReqBatPayRec p_req9188) throws Exception {
        return null;
    }

    /**
     * 批量代收(代扣)结果查询
     */
    @Override
    public RetAtsQryBatPayRec d_9198_QryBatPay(ReqQryBatPayRec p_req9198) throws Exception {
        return null;
    }


    private String[] queryFileStatusAndConfirm(String batchNo, String payAct, Date payDate) {
        try {
            String payFileName = "";
            String bakUpPath = "";
            String tmpLocalMarkPath = "";
            String filePath = "";
            //从SQLlite中取retBatchNo
            Connection conn = FGBiz.getLocalDbConn();
            Map<String, Object> selMap = JDBCHelper.execQuerySingle(conn, SELECTSEQ, new Object[]{batchNo});
            if (selMap != null & selMap.size() > 0) {
                retBatchNo = selMap.get("BANKREQSEQID").toString();
            }

            //查找payDate内的批次号 支付文件名映射文件
            bakUpPath = getDataFileDirectory(payDate);
            tmpLocalMarkPath = StringHelper.trimEnd(bakUpPath, File.separator) + File.separator + "batBatchMap" + File.separator + batchNo + ".txt";
            File payNameFile = new File(tmpLocalMarkPath);
            if (payNameFile.exists()) {
                payFileName = FileHelper.readFileText(tmpLocalMarkPath, getCharset());
                filePath = StringHelper.trimEnd(bakUpPath, File.separator) + File.separator + "batPay" + File.separator + payFileName;
            }
            if ("".equals(payFileName)) {
                WriteBankLogLn("找不到批次号-发送文件名映射文件");
                return new String[]{"-1", "找不到批次号-发送文件名映射文件"};
            }

//            String transCode = getBankConfig().getMapValueByKey("transCode", "1988");
            String transCode = "0080";
            //文件状态标识
            String fileStatus = "";
            //步骤2
            XmlTextWriter xmlWriterStep2 = new XmlTextWriter();
            writeCommonHeader(xmlWriterStep2, transCode, "");
            List<String[]> paramStep2 = new ArrayList<String[]>();
            paramStep2.add(new String[]{"payrollStep", "02"});
            paramStep2.add(new String[]{"batchNo", retBatchNo});
            paramStep2.add(new String[]{"remark1", ""});
            paramStep2.add(new String[]{"remark2", ""});
            writeBodyParams(xmlWriterStep2, paramStep2);
            String[] resultStep2 = sendToBank(xmlWriterStep2.toXmlString());
            if (resultStep2[0].length() == 0) {
                StringBuilder tmpSbMsg = new StringBuilder();
                XmlTextReader tmpBkReader = loadBankRespXmlReader(resultStep2[1], tmpSbMsg);
                if (tmpBkReader != null) {
                    String tmpRetCode = tmpBkReader.getFirstText("/response/head/ret_code");
                    if ("000000".equals(tmpRetCode)) {
                        fileStatus = tmpBkReader.getFirstText("/response/body/fileStatus");
                        WriteBankLogLn("步骤二请求成功，文件" + payFileName + "状态为：" + getBankConfig().getMapValueByKey("fileStatus", fileStatus));
                        if ("9".equals(fileStatus) || "8".equals(fileStatus)) {
                            return new String[]{"-9", tmpBkReader.getFirstText("/response/body/failMsg")};
                        }
                    } else {
                        //return  retCode
                        WriteBankLogLn(tmpBkReader.getFirstText("/response/head/err_msg"));
                        return new String[]{"-2", tmpRetCode, tmpBkReader.getFirstText("/response/head/err_msg")};
                    }
                } else {
                    WriteBankLogLn("步骤二发送成功，银行返回报文解析失败，报文内容为：" + resultStep2[1]);
                    return new String[]{"-1", tmpSbMsg.toString()};
                }
            } else {
                WriteBankLogLn("步骤二内容发送失败：" + resultStep2[1]);
                return new String[]{"-1", resultStep2[1]};
            }

            if ("5".equals(fileStatus)) {
                //步骤3
                XmlTextWriter xmlWriterStep3 = new XmlTextWriter();
                writeCommonHeader(xmlWriterStep3, transCode, "");
                List<String[]> paramStep3 = new ArrayList<String[]>();
                paramStep3.add(new String[]{"payrollStep", "03"});
                paramStep3.add(new String[]{"batchNo", retBatchNo});
                paramStep3.add(new String[]{"accountNo", payAct});
                paramStep3.add(new String[]{"remark1", ""});
                paramStep3.add(new String[]{"remark1", ""});
                writeBodyParams(xmlWriterStep3, paramStep3);
                String[] resultStep3 = sendToBank(xmlWriterStep3.toXmlString());
                String errorMsg = "";
                if (resultStep3[0].length() == 0) {
                    StringBuilder tmpSbMsg = new StringBuilder();
                    XmlTextReader tmpBkReader = loadBankRespXmlReader(resultStep2[1], tmpSbMsg);
                    if (tmpBkReader != null) {
                        String tmpRetCode = tmpBkReader.getFirstText("/response/head/ret_code");
                        if ("000000".equals(tmpRetCode)) {
                            String totalCount = tmpBkReader.getFirstText("/response/body/totalCount");
                            String totalAmount = tmpBkReader.getFirstText("/response/body/totalAmount");
                            WriteBankLogLn("支付请求发起成功，总共：" + totalCount + "笔；总金额：" + totalAmount);
                            return new String[]{"1", "支付请求发起成功，总共：" + totalCount + "笔；总金额：" + totalAmount};
                        } else {
                            //return  retCode
                            WriteBankLogLn(tmpBkReader.getFirstText("/response/head/err_msg"));
                            return new String[]{"-3", tmpRetCode, tmpBkReader.getFirstText("/response/head/err_msg")};
                        }
                    } else {
                        //errorMsg = "步骤三发送成功，银行返回报文解析失败，报文内容为：" + resultStep3[1];
                        errorMsg = tmpSbMsg.toString();
                        WriteBankLogLn(errorMsg);
                    }
                } else {
//                 errorMsg = "步骤三内容发送失败：" + resultStep3[1];
                    errorMsg = resultStep3[1];
                    WriteBankLogLn(errorMsg);
                }
                return new String[]{"-1", errorMsg};
            } else if ("0".equals(fileStatus)) {
                return new String[]{"0", payFileName};
                //测试环境中  支付请求结果完成后fileStatus 仍为10 ?
            } else if ("10".equals(fileStatus)) {
                return new String[]{"0", payFileName};
            } else {
                return new String[]{"-1", getBankConfig().getMapValueByKey("fileStatus", fileStatus)};
            }
        } catch (Exception e) {
            e.printStackTrace();
            return new String[]{"-1", e.getMessage()};
        }
    }

    @Override
    public void run() {
        //等待16分钟后发起支付确认
        WriteBankLogLn("16分钟后将自动发起支付确认。");
        Date date = new Date();
        try {
            Thread.sleep(960000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        WriteBankLogLn2("---------------开始发起支付---------------");
        try {
            login();
        } catch (Exception e) {
            e.printStackTrace();
        }

        queryFileStatusAndConfirm(batchNo, payAct, date);

    }
}
